package com.example.nioprc.infrastructure.client;

import com.example.nioprc.infrastructure.protocol.RpcRequest;
import com.example.nioprc.infrastructure.protocol.RpcResponse;
import com.example.nioprc.infrastructure.serializer.Serializer;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.util.concurrent.*;

/**
 * 改进版基于Java NIO的RPC客户端实现
 */
public class NioRpcClient implements RpcClient {
    private final String host;
    private final int port;
    private final Serializer serializer;
    private final ScheduledExecutorService timeoutExecutor;

    public NioRpcClient(String host, int port, Serializer serializer) {
        this.host = host;
        this.port = port;
        this.serializer = serializer;
        this.timeoutExecutor = Executors.newSingleThreadScheduledExecutor();
    }

    @Override
    public RpcResponse sendRequest(RpcRequest request) {
        try (SocketChannel socketChannel = SocketChannel.open()) {
            socketChannel.connect(new InetSocketAddress(host, port));
            socketChannel.configureBlocking(false);

            // 发送请求（添加长度前缀）
            byte[] requestData = serializer.serialize(request);
            ByteBuffer writeBuffer = ByteBuffer.allocate(4 + requestData.length);
            writeBuffer.putInt(requestData.length);
            writeBuffer.put(requestData);
            writeBuffer.flip();

            while (writeBuffer.hasRemaining()) {
                socketChannel.write(writeBuffer);
            }

            // 读取响应
            return readResponse(socketChannel);
        } catch (IOException e) {
            throw new RuntimeException("Error sending RPC request: " + e.getMessage(), e);
        }
    }

    private RpcResponse readResponse(SocketChannel socketChannel) throws IOException {
        // 读取长度字段
        ByteBuffer lengthBuffer = ByteBuffer.allocate(4);
        while (lengthBuffer.hasRemaining()) {
            if (socketChannel.read(lengthBuffer) == -1) {
                throw new IOException("Connection closed before receiving response");
            }
        }
        lengthBuffer.flip();
        int responseLength = lengthBuffer.getInt();

        // 读取消息体
        ByteBuffer responseBuffer = ByteBuffer.allocate(responseLength);
        while (responseBuffer.hasRemaining()) {
            if (socketChannel.read(responseBuffer) == -1) {
                throw new IOException("Connection closed before receiving full response");
            }
        }
        responseBuffer.flip();
        byte[] responseData = new byte[responseLength];
        responseBuffer.get(responseData);

        // 反序列化响应
        return serializer.deserialize(responseData, RpcResponse.class);
    }


}